#include"CCVideoClient.h"
bool CCVideoClient::m_bKeepAlive = true;
CCVideoClient::CCVideoClient(){
    m_sockfd = -1;
    signal(SIGINT,ClientExitSignalProcess);

    pthread_mutex_init(&m_recvMutex,NULL);
    pthread_mutex_init(&m_sendMutex,NULL);
}
    
CCVideoClient::~CCVideoClient(){
    closeClientSocket();
}
void CCVideoClient::startSocketConnect(CC_NetConnectInfo info){

    printf("ip:%s,port:%d\n",info.server_ip,info.port);
    m_sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(m_sockfd<0){
        printf("create socket failed");
        return;
    }

    struct sockaddr_in sockAddrIn;
    memset(&sockAddrIn,0,sizeof(struct sockaddr_in));
    sockAddrIn.sin_family = AF_INET;
    sockAddrIn.sin_port = htons(info.port);
    sockAddrIn.sin_addr.s_addr = htonl(INADDR_ANY);

    if(inet_pton(AF_INET,info.server_ip,&sockAddrIn.sin_addr.s_addr)<0){
        printf("inet_pton failed");
        return;
    }

    printf("ip:%s,prot:%d",inet_ntoa(sockAddrIn.sin_addr),sockAddrIn.sin_port);

    int flags = fcntl(m_sockfd,F_GETFL,0);
    fcntl(m_sockfd,F_SETFL,flags|O_NONBLOCK);
    int ret = connect(m_sockfd,(struct sockaddr*)&sockAddrIn,sizeof(struct sockaddr_in));
    printf("ret:%d\n",ret);

    detach_thread_creat(NULL,(void*)doWaitConnectThread,(void*)this);
    detach_thread_creat(NULL,(void*)startRecvStreamThread,(void*)this);
    sendKeepAlivePacket();
    return;
}

void CCVideoClient::doWaitConnectThread(long long num){
    CCVideoClient* client = (CCVideoClient*)num;
    if(client){
        client->RunWaitConnect();
    }
}
void CCVideoClient::RunWaitConnect(){
    int error = 0;
    fd_set r_set,w_set;
    FD_ZERO(&r_set);
    FD_ZERO(&w_set);
    FD_SET(m_sockfd,&r_set);
    FD_SET(m_sockfd,&w_set);

    struct timeval timeout ={10,0};
    int retVale = select(m_sockfd+1,&r_set,&w_set,NULL,&timeout);
    switch (retVale)
    {
    case -1:
        printf("select failed");
        break;
    case 0:
        printf("select timeout");
        break;    



    default:
    {
        if(FD_ISSET(m_sockfd,&r_set)&&FD_ISSET(m_sockfd,&w_set)){
            socklen_t len = sizeof(error);
            if(getsockopt(m_sockfd,SOL_SOCKET,SO_ERROR,&error,&len)<0){
                return;//获取SO_ERROR属性选项,也有可能getsockopt返回错误
            }
            printf("error = %d\n",error);
            if(error!=0){//error不为0,则连接失败
                printf("connect failed\n");
                return;
            }

        }
        if(!FD_ISSET(m_sockfd,&r_set)&&FD_ISSET(m_sockfd,&w_set)){//套接字可写不可读,则；连接完成
            printf("success connect");
            m_bconnected = true;

        }
    }break;
    }
}

void CCVideoClient::sendKeepAlivePacket(){
    while(m_bKeepAlive){
        usleep(2000*1000);
        //printf("send keep alive packet");
        if(!m_bconnected){
            printf("unconnected\n");
            continue;
        }
        CC_MsgHeader    msgheader;
        memset((char*)&msgheader,9,sizeof(msgheader));
        strncpy((char*)msgheader.headrID,"GUGU",sizeof(msgheader.headrID));
        msgheader.msgType = MSGHEADER_TYPE_KEEPALIVE;
        msgheader.contentLength=0;
        sendSocketData((char*)&msgheader,sizeof(CC_MsgHeader));
    }
}

void CCVideoClient::ClientExitSignalProcess(int num){
    m_bKeepAlive = false;
}
void CCVideoClient::closeClientSocket(){
    close(m_sockfd);
}

bool CCVideoClient::recvSocketData(char* pbuff,unsigned int length){
    signal(SIGPIPE,SIG_IGN);
    pthread_mutex_lock(&m_recvMutex);
    int recv_len = 0;
    int nRet = 0;

    while(recv_len<length){
        nRet = recv(m_sockfd,pbuff,length-recv_len,0);

        if(nRet<0){
            if(errno == EAGAIN||errno == EINTR||errno==EWOULDBLOCK){
                usleep(10*1000);
                continue;
            }
        }

        if(nRet==-1||nRet==0){
            pthread_mutex_unlock(&m_recvMutex);
            printf("cSeocket recv error");
            return false;
        }
        recv_len+=nRet;
        pbuff+=nRet;
    }
    pthread_mutex_unlock(&m_recvMutex);
    return true;
}

bool CCVideoClient::sendSocketData(char* pbuff,unsigned int length){
    signal(SIGPIPE,SIG_IGN);
    pthread_mutex_lock(&m_sendMutex);
    int send_len = 0;
    int nRet = 0;

    while(send_len<length){
        if(m_sockfd>0){
            nRet = send(m_sockfd,pbuff,length-send_len,0);
            if(nRet<0){
                if(errno == EAGAIN||errno == EINTR||errno==EWOULDBLOCK){
                    usleep(10*1000);
                    continue;
                }
                if(nRet==-1||nRet==0){
                    pthread_mutex_unlock(&m_recvMutex);
                    printf("cSeocket recv error");
                    return false;
                }


            }

            send_len+=nRet;
            pbuff+=nRet;

        }else{
            printf("socket fd error %d\n",m_sockfd);
            pthread_mutex_unlock(&m_sendMutex);
            return false;
        }

        
    }
    //printf("send data over----------\n");
    pthread_mutex_unlock(&m_sendMutex);
    return true;
}

void CCVideoClient::startRecvStreamThread(long long num){
    CCVideoClient* videoRecv = (CCVideoClient*)num;
    if(videoRecv!=NULL){
        videoRecv->RunRecvAVStream();
    }
}

void CCVideoClient::RunRecvAVStream(){
    while (m_bKeepAlive)
    {
        if(m_bconnected==false){
            usleep(10*1000);
            continue;
        }

        CC_MsgHeader header;
        memset((char*)&header,0,sizeof(CC_MsgHeader));

        recvSocketData((char*)&header,sizeof(CC_MsgHeader));

        

        if(strncmp((char*)header.headrID,"GUGU",sizeof(header.headrID))==0){
            
            if(header.msgType==MSGHEADER_TYPE_AVSTREAM){
                if(header.contentLength>0){
                    uint8_t* buff = (uint8_t*)malloc(header.contentLength);
                    recvSocketData((char*)buff,header.contentLength);
                    printf("Recvd ac stream... %d\n",header.contentLength);

                    for(int i=0;i<10;i++){
                        printf(" %x",buff[i]);
                    }
                    printf("\n");
                    free(buff);
                }
            }
            
        }
        usleep(1*1000);
    }
    
}